package cn.chencq.proxy.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.InetSocketAddress;
import java.net.JarURLConnection;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;

import cn.chencq.proxy.constants.RedisKey;

import com.limei.adplatform.redis.cluster.RedisClusterFactory;

public class Util {

	// 通过网址获取host
	public static String getHost(String url) {
		String host = "";
		Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
		Matcher matcher = p.matcher(url);
		if (matcher.find()) {
			host = matcher.group();
		}
		return host;
	}

	/**
	 * 设置代理
	 * 
	 * @param ip
	 * @param port
	 * @return
	 */
	public static Proxy setProxy(String ip, String port) {
		SocketAddress addr = new InetSocketAddress(ip, Integer.parseInt(port));
		Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
		return proxy;
	}

	/**
	 * 设置代理
	 * 
	 * @param str
	 *            (ip:port)
	 * @return
	 */
	public static Proxy setProxy(String str) {
		if(str=="" || str==null){
			return null;
		}
		
		String ip = str.split(":")[0];
		String port = str.split(":")[1];
		SocketAddress addr = new InetSocketAddress(ip, Integer.parseInt(port));
		Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
		return proxy;
	}

	/**
	 * 取出有效代理ip </br>
	 * 
	 * 1.当尝试10次都没有获取到有效的代理,则返回null </br>
	 * 
	 * 2.当获取到有效代理，则返回该代理
	 * 
	 * @return
	 */
	public static Proxy getProxy() {
		Proxy proxy = null;
		int tryTime = 0;
		boolean checkStatus = false;
		do {
			String p = RedisClusterFactory.srandmember(RedisKey.getClusterName(), RedisKey.getVaildProxyKey());
			proxy = Util.setProxy(p);
			checkStatus = checkProxy("http://1212.ip138.com/ic.asp", proxy);
			tryTime += 1;
		} while (tryTime < 10 || !checkStatus);

		if (checkStatus) {
			return proxy;
		}

		return null;
	}

	public static boolean checkProxy(String url, Proxy proxy) {
		boolean ret = false;
		Connection con = Jsoup.connect(url);
		if(proxy!=null){
			con.proxy(proxy);
		}
		
		String host = getHost(url);
		con.header("Host", host);
		con.header("User-Agent", 
				"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36");
		try {
			Response res = con.ignoreContentType(true).timeout(3000).method(Method.GET).execute();
			if (res.statusCode() == 200) {
				ret = true;
			}
		} catch (Exception e) {

		}
		return ret;
	}

	public static String getDateFormat(String format, Date date) {
		SimpleDateFormat dateFormat = new SimpleDateFormat(format);
		return dateFormat.format(date);
	}


	public static Set<Class<?>> getClasses(String pack) {

		// 第一个class类的集合
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
		// 是否循环迭代
		boolean recursive = true;
		// 获取包的名字 并进行替换
		String packageName = pack;
		String packageDirName = packageName.replace('.', '/');
		// 定义一个枚举的集合 并进行循环来处理这个目录下的things
		Enumeration<URL> dirs;
		try {
			// 当前线程的类加载器
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			// 循环迭代下去
			while (dirs.hasMoreElements()) {
				// 获取下一个元素
				URL url = dirs.nextElement();
				// 得到协议的名称
				String protocol = url.getProtocol();
				// 如果是以文件的形式保存在服务器上
				if ("file".equals(protocol)) {
					// 获取包的物理路径
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					// 以文件的方式扫描整个包下的文件 并添加到集合中
					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else if ("jar".equals(protocol)) {
					JarFile jar;
					try {
						// 获取jar
						jar = ((JarURLConnection) url.openConnection()).getJarFile();
						// 从此jar包 得到一个枚举类
						Enumeration<JarEntry> entries = jar.entries();
						// 同样的进行循环迭代
						while (entries.hasMoreElements()) {
							// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							// 如果是以/开头的
							if (name.charAt(0) == '/') {
								// 获取后面的字符串
								name = name.substring(1);
							}
							// 如果前半部分和定义的包名相同
							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');
								// 如果以"/"结尾 是一个包
								if (idx != -1) {
									// 获取包名 把"/"替换成"."
									packageName = name.substring(0, idx).replace('/', '.');
								}
								// 如果可以迭代下去 并且是一个包
								if ((idx != -1) || recursive) {
									// 如果是一个.class文件 而且不是目录
									if (name.endsWith(".class") && !entry.isDirectory()) {
										// 去掉后面的".class" 获取真正的类名
										String className = name.substring(packageName.length() + 1, name.length() - 6);
										try {
											// 添加到classes
											classes.add(Class.forName(packageName + '.' + className));
										} catch (ClassNotFoundException e) {
											// log
											// .error("添加用户自定义视图类错误 找不到此类的.class文件");
											System.out.println(packageName + '.' + className);
											e.printStackTrace();
										}
									}
								}
							}
						}
					} catch (IOException e) {
						// log.error("在扫描用户定义视图时从jar包获取文件出错");
						e.printStackTrace();
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return classes;
	}

	/**
	 * 以文件的形式来获取包下的所有Class
	 * 
	 * @param packageName
	 * @param packagePath
	 * @param recursive
	 * @param classes
	 */
	public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
		// 获取此包的目录 建立一个File
		File dir = new File(packagePath);
		// 如果不存在或者 也不是目录就直接返回
		if (!dir.exists() || !dir.isDirectory()) {
			// log.warn("用户定义包名 " + packageName + " 下没有任何文件");
			return;
		}
		// 如果存在 就获取包下的所有文件 包括目录
		File[] dirfiles = dir.listFiles(new FileFilter() {
			// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
			public boolean accept(File file) {
				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
			}
		});
		// 循环所有文件
		for (File file : dirfiles) {
			// 如果是目录 则继续扫描
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
			} else {
				// 如果是java类文件 去掉后面的.class 只留下类名
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					// 添加到集合中去
					// classes.add(Class.forName(packageName + '.' +
					// className));
					// 经过回复同学的提醒，这里用forName有一些不好，会触发static方法，没有使用classLoader的load干净
					classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 判断class是否是抽象类
	 * 
	 * @param cla
	 * @return
	 */
	public static boolean isAbstract(Class<?> cla) {
		int modifiors = cla.getModifiers();

		return Modifier.isAbstract(modifiors);
	}

	/**
	 * 生成请求rid
	 * 
	 * @return
	 */
	public static String generateRID() {
		String rid = System.currentTimeMillis() + "" + new Random().nextInt(10000);

		return rid;
	}
	
	/**
	 * set 转成数组
	 * @param set
	 * @return
	 */
	public static String[] setToArray(Set<String> set) {
		if (set != null && set.size() > 0) {
			String[] memebers = new String[set.size()];
			set.toArray(memebers);
			return memebers;
		}
		return null;
	}

	/**
	 * list转成set
	 * @param list
	 * @return
	 */
	public static Set<String> listToSet(List<String> list) {
		Set<String> set = new HashSet<String>();
		if(list!=null){
			set.addAll(list);
		}
		return set;
	}

}
